﻿/********************************************************************
	created:	2012/02/26   23:21
	filename: 	hy_thread.h
	author:		supercaco@sina.com
	purpose:	
*********************************************************************/
#ifndef _HY_THREAD_H_
#define _HY_THREAD_H_

#if defined(_WIN32)
	#include <winsock2.h>
	#include <Windows.h>
	#include <process.h>
#else
	#include <pthread.h>
#endif

#include <memory> 

// inner callback
namespace inner {
	/** 线程function */
	template < typename Handler, typename Arg1>
	class callback1
	{
	public:
		callback1(const Handler handler,Arg1 arg)
			: handler_(handler),arg1_(arg)
		{
		}

		void operator()()
		{
			handler_(arg1_);			
		}

		void operator()() const
		{
			handler_(arg1_);
		}

	private:
		Handler handler_;
		Arg1    arg1_;
	};

	/** 线程function */
	template < typename Handler, typename ClassType, typename Arg1>
	class obj_callback1
	{
	public:
		obj_callback1(Handler handler, ClassType ptr,Arg1 arg1 )
			: handler_(handler),
			Obj_(ptr),
			Arg1_(arg1)
		{
		}

		void operator()()
		{
			(Obj_->*handler_)((void*)Arg1_);
		}

		void operator()() const
		{
			(Obj_->*handler_)((void*)Arg1_);
		}

	private:
		Handler		handler_;
		ClassType	Obj_;
		Arg1		Arg1_;
	};

}//namespace inner

/** thread bind function */
template <typename Handler, typename Arg1>
inline inner::callback1<Handler,Arg1> bind_thread(const Handler handler,Arg1 arg1)
{
	return inner::callback1<Handler,Arg1>(handler,arg1);
}

/** thread bind function */
template <typename Handler, typename ObjPtr, typename Arg1>
inline inner::obj_callback1<Handler, ObjPtr,Arg1> bind_thread(
	const Handler handler,ObjPtr ptr, Arg1 arg1)
{
	return inner::obj_callback1<Handler, ObjPtr,Arg1>(handler, ptr, arg1);
}


enum
{
	hy_thread_init,
	hy_thread_running,
	hy_thread_stop
};

#if defined(_WIN32)

unsigned int __stdcall win_thread_function(void* arg);

#if defined(WINVER) && (WINVER < 0x0500)
	void __stdcall apc_function(ULONG data);
#else
	void __stdcall apc_function(ULONG_PTR data);
#endif //defined(WINVER) && (WINVER < 0x0500)



template <typename T>
class win_thread_base
{
public:
	static bool terminate_threads()
	{
		return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0;
	}

	static void set_terminate_threads(bool b)
	{
		::InterlockedExchange(&terminate_threads_, b ? 1 : 0);
	}

private:
	//线程数量
	static long terminate_threads_;
};

//线程总数量

template <typename T> 
long win_thread_base<T>::terminate_threads_ = 0;

class win_thread
	: //private zr_noncopyable,
	public win_thread_base<win_thread>
{
public:
	// Constructor.
	template <typename Function>
	win_thread(Function f)
		: exit_event_(0),status_(hy_thread_init)
	{
		std::auto_ptr<func_base> arg(new func<Function>(f));

		::HANDLE entry_event = 0;
		arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
		if (entry_event == NULL)
		{
			return;
		}

		arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
		if (exit_event_ == NULL)
		{
			::CloseHandle(entry_event);
			return;
		}

		unsigned int thread_id = 0;
		thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 0, win_thread_function, arg.get(), 0, &thread_id));
		if (thread_ == 0)
		{
			if (entry_event)
				::CloseHandle(entry_event);
			if (exit_event_)
				::CloseHandle(exit_event_);
			status_ = hy_thread_stop;
			return;
		}
		arg.release();

		if (entry_event != NULL)
		{
			::WaitForSingleObject(entry_event, INFINITE);
			::CloseHandle(entry_event);
			status_ = hy_thread_running;
		}
	}

	// Destructor.
	~win_thread()
	{
		::CloseHandle(thread_);
	}

	// Wait for the thread to exit.
	void join()
	{
		::WaitForSingleObject(exit_event_, INFINITE);
		::CloseHandle(exit_event_);
		if (win_thread_base::terminate_threads())
		{
			::TerminateThread(thread_, 0);
		}
		else
		{
			::QueueUserAPC(apc_function, thread_, 0);
			::WaitForSingleObject(thread_, INFINITE);
		}
		status_ = hy_thread_stop;
	}

	int status()
	{
		return status_;
	}

private:
	friend unsigned int __stdcall win_thread_function(void* arg);

	class func_base
	{
	public:
		virtual ~func_base() {}
		virtual void run() = 0;
		::HANDLE entry_event_;
		::HANDLE exit_event_;
	};

	template <typename Function>
	class func
		: public func_base
	{
	public:
		func(Function f)
			: f_(f)
		{
		}

		virtual void run()
		{
			f_();
		}

	private:
		Function f_;
	};

	volatile int status_; //
	::HANDLE thread_;
	::HANDLE exit_event_;
};

inline unsigned int __stdcall win_thread_function(void* arg)
{
	std::auto_ptr<win_thread::func_base> func(
		static_cast<win_thread::func_base*>(arg));

	::SetEvent(func->entry_event_);

	func->run();

	// Signal that the thread has finished its work, but rather than returning go
	// to sleep to put the thread into a well known state. If the thread is being
	// joined during global object destruction then it may be killed using
	// TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx
	// call will be interrupted using QueueUserAPC and the thread will shut down
	// cleanly.
	HANDLE exit_event = func->exit_event_;
	func.reset();
	::SetEvent(exit_event);
	::SleepEx(INFINITE, TRUE);

	return 0;
}

#if defined(WINVER) && (WINVER < 0x0500)
inline void __stdcall apc_function(ULONG) {}
#else
inline void __stdcall apc_function(ULONG_PTR) {}
#endif


#else  //_WIN32

extern "C" void* posix_thread_function(void* arg);

class posix_thread
	//: private zr_noncopyable
{
public:
	// Constructor.
	template <typename Function>
	posix_thread(Function f)
		: joined_(false),status_(hy_thread_init)
	{
		std::auto_ptr<func_base> arg(new func<Function>(f));
		int error = ::pthread_create(&thread_, 0, posix_thread_function, arg.get());
		//if (error != 0)
		//{
		//	zr_throw(zr_get_os_error());
		//}
		status_ = hy_thread_running;
		arg.release();
	}

	// Destructor.
	~posix_thread()
	{
		if (!joined_)
		{
			::pthread_detach(thread_);
			status_ = hy_thread_stop;
		}
	}

	// Wait for the thread to exit.
	void join()
	{
		if (!joined_)
		{
			::pthread_join(thread_, 0);
			joined_ = true;
			status_ = hy_thread_stop;
		}
	}

	int status()
	{
		return status_;
	}
private:
	friend void* posix_thread_function(void* arg);

	class func_base
	{
	public:
		virtual ~func_base() {}
		virtual void run() = 0;
	};

	template <typename Function>
	class func
		: public func_base
	{
	public:
		func(Function f)
			: f_(f)
		{
		}

		virtual void run()
		{
			f_();
		}

	private:
		Function f_;
	};

	volatile int status_; //
	::pthread_t thread_;
	bool joined_;
};

inline void* posix_thread_function(void* arg)
{
	std::auto_ptr<posix_thread::func_base> f(
		static_cast<posix_thread::func_base*>(arg));
	f->run();
	return 0;
}

#endif  //_WIN32


#if defined(_WIN32)
	typedef win_thread		hy_thread;
#else
	typedef posix_thread	hy_thread;
#endif


#endif  //_HY_THREAD_H_
